# -*- coding: utf-8 -*-

import sys
from PyQt4 import QtGui,QtCore
from xmpp.c2s_test import MyClient
from xmpp.c2s_test import Disconnected
import logging
import threading
import libxml2
import logic.thread_msgs
from pyxmpp.all import JID,Iq,Presence,Message,StreamError
import traceback
import time
from ui.logon_ui import LogonUI
from ui.logic_ui import LogicUI
from ui.chat_ui import ChatUI
from logic import thread_msgs

import base64
from pyDes import *

import ConfigParser
import re

from pyxmpp.jabber.client import JabberClient

class Registration(JabberClient):
    def __init__(self,jid=None, password=None, server=None, port=5222, deviceid=None,logicthread=None,
            auth_methods=("sasl:DIGEST-MD5","digest"),
            tls_settings=None, keepalive=0,
            disco_name=u"pyxmpp based Jabber client", disco_category=u"client",
            disco_type=u"pc"):
        JabberClient.__init__(self, jid=jid,password=password,server=server,port=port,auth_methods=auth_methods,
                              tls_settings=tls_settings,keepalive=keepalive,disco_name=disco_name,disco_category=disco_category,
                              disco_type=disco_type)
        self.logicthread = logicthread
        self.deviceid = deviceid
        self.currentdeviceid = deviceid        
    
    def registration(self):
        """Submit a registration form

        :Parameters:
            - `form`: the form to submit
        :Types:
            - `form`: `pyxmpp.jabber.dataforms.Form`"""
            
#<iq id="0279m-1" to="register.domain" type="get">
#    <query xmlns="jabber:iq:register">
#        <uniqueid>1112233445566778899</uniqueid>
#        <email>kote002@sina.com</email>
#        <password>111111</password>
#        <intorduction>1455555</intorduction>
#        <sex>male</sex>
#        <nick>shuishi</nick>
#        <birthday>1944-11-12</birthday>
#        <largeavatar>http://ip:port/PhotoServlet?fileid=fdsafa</largeavatar>
#        <smallavatar>http://ip:port/PhotoServlet?fileid=fdssaf</smallavatar>
#    </query>
#</iq>
            
        iq = Iq(to_jid=JID("register.mk"), stanza_type="get")
        q = iq.new_query("jabber:iq:register")        
        q.newChild(q.ns(),"uniqueid",str(self.currentdeviceid))
        
        k = des(key="moblover", mode=CBC, IV="moblover", pad=None, padmode=PAD_PKCS5)
        desemail = k.encrypt(str(self.currentdeviceid+"@py.com"))        
        desbase64email = base64.encodestring(desemail)
        
        despass = k.encrypt(str(self.currentdeviceid))        
        desbase64pass = base64.encodestring(despass)
        
        q.newChild(q.ns(),"email",desbase64email),
        q.newChild(q.ns(),"password",desbase64pass),
        
        sexstr = "female"
        pattern = re.compile(r"(?P<prefix>.*)_(?P<count>\d+)")
        deviceidstr = self.currentdeviceid
        deviceidmatch = pattern.match(deviceidstr)
        if (deviceidmatch):                            
            count = deviceidmatch.group("count")
            if (int(count)%2==0):
                sexstr="male"
        q.newChild(q.ns(),"sex",sexstr),
        q.newChild(q.ns(),"nick",str(self.currentdeviceid)),        
                
        resiq = Iq(stanza_id=iq.get_id(),to_jid=JID("mk"),stanza_type="get")
        resiq.new_query("jabber:iq:register")
        self.stream.set_response_handlers(resiq,
                                          self.__register_result,self.__register_error)
        self.stream.send(iq)
    
    def __register_result(self, iq):
        accountinfo=iq.xpath_eval("g:query/g:account",{"g":"jabber:iq:register"})
#        for account in accountinfo:
#            sysusername_encrypted = account.prop("uid")
#            password_encrypted = account.prop("password")            
#            k = des(key="moblover", mode=CBC, IV="moblover", pad=None, padmode=PAD_PKCS5)
#            sysusername =  k.decrypt(base64.decodestring(sysusername_encrypted), padmode=PAD_PKCS5)
#            password =  k.decrypt(base64.decodestring(password_encrypted), padmode=PAD_PKCS5)
#            self.logicthread.user_registered(sysusername, password, self.currentdeviceid)
        print ("%r registered success", self.currentdeviceid)
        self.disconnect()
            
#        pattern = re.compile(r"(?P<prefix>.*)_(?P<count>\d+)")
#        deviceidstr = self.currentdeviceid
#        deviceidmatch = pattern.match(deviceidstr)
#        if (deviceidmatch):
#            deviceid = deviceidmatch.group("prefix")                
#            count = deviceidmatch.group("count")
#            if (int(count)>0):
#                self.currentdeviceid = str(deviceid)+'_'+str(int(count)-1)
#                self.currentdeviceid
#                self.registration()

#            try:               
#                config = ConfigParser.ConfigParser()
#                configfp = open('config.ini', 'w+')                   
#                config.readfp(configfp)             
#                count = int(config.get("users", "count"))
#                count = count+1
#                config.set("users", "count", count)
#                userkey = "user"+str(count-1)
#                config.add_section(userkey)
#                config.set(userkey, "name", sysusername+"[R]")
#                config.set(userkey, "username", sysusername)
#                config.set(userkey, "password", password)     
#                config.set(userkey, "deviceid", self.currentdeviceid)                           
#                config.write(configfp)
#                configfp.close()
#            except:
#                pass
#            self.logicthread.read_config()                        
    
    def __register_error(self, iq):
        print ("%r registered failed", self.currentdeviceid)
        
#        pattern = re.compile(r"(?P<prefix>.*)_(?P<count>\d+)")
#        deviceidstr = self.currentdeviceid
#        deviceidmatch = pattern.match(deviceidstr)
#        if (deviceidmatch):
#            deviceid = deviceidmatch.group("prefix")                
#            count = deviceidmatch.group("count")
#            if (int(count)>0):
#                self.currentdeviceid = str(deviceid)+'_'+str(int(count)-1)
#                self.currentdeviceid
#                self.registration()

class DispatchThread(threading.Thread):
    def __init__(self):
        self.cfgusers = []        
        self.read_config()        
        threading.Thread.__init__(self)
        self.logon_ui = None
        self.logic_ui = None
        self.chat_ui = None
        
        self.logicthreads = []
        self.registerclient = None
        
    def read_config(self):
        try:            
            config = ConfigParser.ConfigParser()                         
            config.readfp(open('config.ini'))            
            self.im_ip = config.get("imserver","ip")
            self.im_port = int(config.get("imserver","port"))
            
            config.readfp(open('users.ini'))
            self.cfgusers = dict()
            count = int(config.get("users", "count"))
            for i in range(0, count):
                name = config.get("user"+str(i), "name")
                username = config.get("user"+str(i), "username")
                password = config.get("user"+str(i), "password")
                deviceid = config.get("user"+str(i), "deviceid")
                self.cfgusers[name] = dict()
                self.cfgusers[name]['username']=username
                self.cfgusers[name]['password']=password
                self.cfgusers[name]['deviceid']=deviceid
        except:
            pass    
    
    def run(self):
        libxml2.debugMemory(1)        
        self.logon_ui.add_cfg_users(self.cfgusers)
                
        logger=logging.getLogger()
        logger.addHandler(logging.StreamHandler())
        logger.setLevel(logging.DEBUG)  
        
        self.thread_msgs = []        
        msg_calls = {thread_msgs.TYPE_LOGON:self.__logon_msg, 
                     #thread_msgs.TYPE_DISCONNECT:self.__disconnect_msg,
                     #thread_msgs.TYPE_DATE_REQUEST:self.__date_req_msg,
                     #thread_msgs.TYPE_SITDOWN:self.__sit_down_msg,
                     thread_msgs.TYPE_REGISTER:self.__register_msg}
        self.lock = threading.Lock()
        
        while True:            
            if (self.lock.acquire()):
                for msg in self.thread_msgs:
                    if (msg_calls.has_key(msg.type)):
                        msg_calls[msg.type](msg)                    
                self.thread_msgs = []
                self.lock.release()            
            
#            if self.registerclient:
#                #xmpp loop
#                try:
#                    try:
#                        stream=self.registerclient.get_stream()
#                        if stream:
#                            act=stream.loop_iter(0.001)
#                            if not act:
#                                self.registerclient.idle()
#                    except:
#                        self.registerclient.disconnect()
#                        self.registerclient = None                
#                    finally:
#                        pass        
#                except (StreamError,Disconnected),_e:
#                    self.registerclient = None
                    
            time.sleep(0.01)            
                        
        libxml2.cleanupParser()
        if libxml2.debugMemory(1) == 0:
            print "OK"
        else:
            print "Memory leak %d bytes" % (libxml2.debugMemory(1))
            libxml2.dumpMemory()
            
    def __logon_msg(self, msg):
        if (self.logicthreads!=[]):
            return        
        
        pattern = re.compile(r"(?P<prefix>.*)_(?P<count>\d+)")
        currentdeviceid = msg.deviceid                        
        deviceidmatch = pattern.match(currentdeviceid)
        if (deviceidmatch):
                deviceid = deviceidmatch.group("prefix")
                count = deviceidmatch.group("count")
        totalthreads = int(count)/200+1
        for _i in range(0,totalthreads):
            newthread = LogicThread(self.logon_ui, self.logic_ui, self.chat_ui)
            self.logicthreads.append(newthread)
            newthread.start()
                
        threadindex = 0
        while (int(count)>1):
            deviceidmatch = pattern.match(currentdeviceid)
            if (deviceidmatch):
                deviceid = deviceidmatch.group("prefix")
                count = deviceidmatch.group("count")
            email = currentdeviceid
            password = currentdeviceid
            
            self.logicthreads[threadindex].post_msg(thread_msgs.MsgLogon(email, password, currentdeviceid))
            
            currentdeviceid = str(deviceid)+'_'+str(int(count)-1)
            
            threadindex = (threadindex+1)%totalthreads
            
    
    def __register_msg(self, msg):
#        if (self.registerclient):
#            print("registering instance already created")
#            self.registerclient.deviceid = msg.deviceid
#            self.registerclient.currentdeviceid = msg.deviceid
#            self.registerclient.registration()
#            return
#        print("register msg")
#        self.registerclient = Registration(jid=JID("xxx@mk/xxx"),server=self.im_ip,port=self.im_port,deviceid=msg.deviceid,logicthread=self)
#        self.registerclient.connect(True)  
#        self.registerclient.registration()   
        if (self.logicthreads!=[]):
            return        
        
        pattern = re.compile(r"(?P<prefix>.*)_(?P<count>\d+)")
        currentdeviceid = msg.deviceid                        
        deviceidmatch = pattern.match(currentdeviceid)
        if (deviceidmatch):
                deviceid = deviceidmatch.group("prefix")
                count = deviceidmatch.group("count")
        totalthreads = int(count)/200+1
        for _i in range(0,totalthreads):
            newthread = LogicThread(self.logon_ui, self.logic_ui, self.chat_ui)
            self.logicthreads.append(newthread)
            newthread.start()
                
        threadindex = 0
        while (int(count)>1):
            deviceidmatch = pattern.match(currentdeviceid)
            if (deviceidmatch):
                deviceid = deviceidmatch.group("prefix")
                count = deviceidmatch.group("count")
            email = currentdeviceid
            password = currentdeviceid
            
            self.logicthreads[threadindex].post_msg(thread_msgs.MsgRegister(currentdeviceid))
            
            currentdeviceid = str(deviceid)+'_'+str(int(count)-1)
            
            threadindex = (threadindex+1)%totalthreads
             
    
    def user_registered(self, username, password, deviceid):
        pass    

    def post_msg(self, msg):
        if (self.lock.acquire()):
            self.thread_msgs.append(msg)
            self.lock.release()
            
            
class LogicThread(threading.Thread):
    def __init__(self, logon_ui, logic_ui, chat_ui):
        self.im_ip = "127.0.0.1"
        self.im_port = "5222"
        threading.Thread.__init__(self)
        self.logon_ui = logon_ui
        self.logic_ui = logic_ui
        self.chat_ui = chat_ui
        self.lock = threading.Lock()
        self.thread_msgs = []
        
        self.registerclients = []
        
        try:
            config = ConfigParser.ConfigParser()                         
            config.readfp(open('config.ini'))            
            self.im_ip = config.get("imserver","ip")
            self.im_port = int(config.get("imserver","port"))
        except:
            pass
        
    def user_disconnected(self, clientinstance):
        jidstr = clientinstance.jid.as_string()
        self.clientmap.pop(jidstr)
        self.clientmap.keys()        
    
    def run(self):                
        logger=logging.getLogger()
        logger.addHandler(logging.StreamHandler())
        logger.setLevel(logging.DEBUG)  
                        
        self.clientmap = dict()
        
        msg_calls = {thread_msgs.TYPE_LOGON:self.__logon_msg, 
                     thread_msgs.TYPE_DISCONNECT:self.__disconnect_msg,
                     thread_msgs.TYPE_DATE_REQUEST:self.__date_req_msg,
                     thread_msgs.TYPE_SITDOWN:self.__sit_down_msg,
                     thread_msgs.TYPE_REGISTER:self.__register_msg}               
        
        while True:            
            if (self.lock.acquire()):
                for msg in self.thread_msgs:
                    if (msg_calls.has_key(msg.type)):
                        msg_calls[msg.type](msg)                    
                self.thread_msgs = []
                self.lock.release()
            
            for item in self.clientmap.keys():
                clientinstance = self.clientmap[item] 
                if (clientinstance):
                    #xmpp loop
                    try:
                        try:
                            stream=clientinstance.get_stream()
                            if stream:
                                act=stream.loop_iter(0.001)
                                if not act:
                                    clientinstance.idle()
                        except:
                            clientinstance.disconnect()
                            clientinstance = None                
                        finally:
                            pass        
                    except (StreamError,Disconnected),_e:
                        clientinstance = None
                        
            for item in self.registerclients:
                try:
                    try:
                        stream=item.get_stream()
                        if stream:
                            act=stream.loop_iter(0.001)
                            if not act:
                                item.idle()
                    except:
                        item.disconnect()
                        item = None                
                    finally:
                        pass        
                except (StreamError,Disconnected),_e:
                    item = None
                        
            time.sleep(0.01)            

    def __register_msg(self, msg):
        newclient = Registration(jid=JID("xxx@mk/xxx"),server=self.im_ip,port=self.im_port,deviceid=msg.deviceid,logicthread=self)
        newclient.connect(True)  
        newclient.registration()
        self.registerclients.append(newclient)
            
    def __logon_msg(self, msg):        
        msgjid=JID(msg.username+"@mk"+"/win32")
        msgjidstr = msgjid.as_string()
        if (self.clientmap.has_key(msgjidstr)):
            print ("%r already logined" % msgjidstr)
            return
        print "creating stream..."        
        clientinstance=MyClient(jid=msgjid,
                             password=msg.password,
                             deviceid=msg.deviceid,                   
                             server=self.im_ip, port=self.im_port)
        clientinstance.thread = self
        clientinstance.logon_ui = self.logon_ui
        clientinstance.logic_ui = self.logic_ui
        clientinstance.chat_ui = self.chat_ui
        
        print "connecting..."
        try:
            clientinstance.connect()
            self.clientmap[msgjidstr] = clientinstance            
        except:
            print "connect failed"
            #self.logic_ui.hide()
            #clientinstance.logon_ui.logic_logon_failed()
            clientinstance = None
        finally:
            pass
        
    def __disconnect_msg(self, msg):
        print("%r disconnectmsg" % msg.selfjidstr)  
        if (self.clientmap.has_key(msg.selfjidstr)):
            self.clientmap[msg.selfjidstr].disconnect()                            
        
    def __sit_down_msg(self, msg):
        print(msg.selfjidstr+" sitdown "+msg.scene+":"+msg.desk)  
        self.clientinstance.sit_down(msg.scene, msg.desk)         
    
    def __date_req_msg(self, msg):
        print(msg.selfjidstr+" datereq "+msg.jidstr)
            
    def post_msg(self, msg):
        if (self.lock.acquire()):
            self.thread_msgs.append(msg)
            self.lock.release()
    

def main():
    'main function'    
    logicthread = DispatchThread()    
    
    app = QtGui.QApplication(sys.argv)    
    logic_ui = LogicUI(logicthread)
    logic_ui.mainwindow.show()
    logon_ui = LogonUI(logicthread) 
    #chat_ui = ChatUI(logicthread)
    logicthread.logon_ui = logon_ui
    logicthread.logic_ui = logic_ui
    logic_ui.logon_dlg = logon_ui.dlg
    #logicthread.chat_ui = chat_ui    
    
    logicthread.start()
    sys.exit( app.exec_() )
    sys.exit( logicthread )    

if __name__ == '__main__':
    main()
    